package tmt.usercenter.web.service;

import com.tmt.helper.DateHelper;
import com.tmt.sm.ISmSender;
import com.tmt.sm.impl.ReturnMode;
import com.tmt.sm.impl.SendResult;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tmt.usercenter.web.bean.TmtSemaphore;
import tmt.usercenter.web.domain.ClientSystem;
import tmt.usercenter.web.domain.SmHistory;
import tmt.usercenter.web.domain.enums.FuncPointType;
import tmt.usercenter.web.domain.enums.SmStatus;
import tmt.usercenter.web.domain.enums.SystemParamCode;
import tmt.usercenter.web.repository.ISmHistoryRepo;
import tmt.usercenter.web.vo.HttpResult;

import java.util.Arrays;
import java.util.Date;

@Service
@Transactional(rollbackFor = Exception.class)
public class SmHistoryService extends TmtBaseService<SmHistory, Long> {

    @Getter
    private ISmHistoryRepo iSmHistoryRepo;

    private ISmSender smSendService;

    private ClientSystemService clientSystemService;

    private SystemParamService paramService;

    private SemaphoreService semaphoreService;

    @Autowired
    public SmHistoryService(ISmHistoryRepo iSmHistoryRepo,
                            ClientSystemService clientSystemService,
                            ISmSender smSendService,
                            SystemParamService paramService,
                            SemaphoreService semaphoreService) {
        super(iSmHistoryRepo, Arrays.asList(clientSystemService));
        this.iSmHistoryRepo = iSmHistoryRepo;
        this.clientSystemService = clientSystemService;
        this.smSendService = smSendService;
        this.paramService = paramService;
        this.semaphoreService = semaphoreService;
    }

    public HttpResult<String> sendSm(String clientId, String mobile, String content,
                                     FuncPointType funcPoint, boolean valid, ReturnMode returnMode) {

        boolean enable = paramService.getSystemParamValue(SystemParamCode.ENABLE_SM_SERVICE, boolean.class);
        if (!enable) {
            return HttpResult.failure("用户中心外部短信发送服务未激活");
        }

        SendResult result = null;
        TmtSemaphore semaphore = semaphoreService.getSemaphore(SmHistory.class, Long.parseLong(mobile));
        semaphore.acquire();
        try {
            ClientSystem clientSystem = clientSystemService.findByClientId(clientId);
            if (clientSystem.getSendTotals() >= clientSystem.getSmTotals()) {
                return HttpResult.failure("允许发送的短信条数为0");
            }

            SmHistory smHistory = iSmHistoryRepo.findFirstByToMobileOrderByCreateTimeDesc(mobile);
            if (smHistory != null) {
                int minutes = paramService.getSystemParamValue(SystemParamCode.SM_INTERVAL_MINUTES, int.class);
                if (smHistory.getCreateTime().after(DateHelper.addMinutes(new Date(), -minutes))) {
                    return HttpResult.failure(String.format("同一电话号码%s分钟内不可再次请求发送短信", minutes));
                }
            }

            //对找回密码做个频率限制。
            if (FuncPointType.RESET_PASSWORD == funcPoint) {
                int maxCount = maxSendInDay();
                Date curDate = DateHelper.parseDate(DateHelper.formatDate(new Date(), "yyyy-MM-dd"));
                int count = iSmHistoryRepo.countByFuncPointAndToMobileAndSmStatus(funcPoint, mobile, curDate);
                if (count >= maxCount) {
                    return HttpResult.failure("目标帐户今日重置密码次数已耗尽，请次日重新尝试！");
                }
            }

            //此处调用短信同步发送接口。
            result = smSendService.send(mobile, content, null, returnMode);

            //创建短信发送记录
            smHistory = SmHistory.newInstance(mobile, content, result.getSender(),
                    new Date(), result.getOriginResult(), funcPoint,
                    result.isSuccess() ? SmStatus.SEND_SUCCESS : SmStatus.SEND_FAILURE,
                    clientSystem, valid, true);

            create(smHistory);

            //累计已发送条数
            clientSystem.setSendTotals(clientSystem.getSendTotals() + 1);
            clientSystemService.update(clientSystem);
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            semaphore.release();
        }

        String info = "验证码";
        switch (funcPoint) {
            case RESET_PASSWORD:
                info = "最新密码";
                break;
        }

        return result != null && result.isSuccess() ? HttpResult.success(String.format("%s发送成功", info))
                : HttpResult.failure(String.format("%s发送失败:%s%s", info,
                (result != null ? result.getResultMsg() : "本地调用异常"),
                (result != null ? " (" + result.getResultCode() + ")" : "")));
    }

    @Transactional(readOnly = true)
    public SmHistory findLastValidByToMobileAndFuncPoint(String mobile, FuncPointType funcPoint) {
        return iSmHistoryRepo.findFirstByToMobileAndFuncPointAndValidOrderByIdDesc(mobile, funcPoint, true);
    }

    public void updateValid(Long id, boolean valid) {
        SmHistory history = iSmHistoryRepo.findById(id);
        if (history != null) {
            history.setValid(valid);
            iSmHistoryRepo.save(history);
        }
    }

    /**
     * 每天可发送的最大次数。
     *
     * @return
     */
    private int maxSendInDay() {
        int maxCount = 1;
        try {
            String param = paramService.getSystemParamValue(SystemParamCode.RETRIEVE_PASSWORD_MODE, String.class);
            String[] subParams = param.split("\\|");
            maxCount = Integer.parseInt(subParams[1]);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return maxCount;
    }
}
